﻿using System;
using System.Runtime.InteropServices;

namespace V8.Net
{
    // ========================================================================================================================

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public unsafe struct NativeV8EngineProxy
    {
        public ProxyObjectType NativeClassType;
        public Int32 ID;
    }

    // ========================================================================================================================

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public unsafe struct NativeObjectTemplateProxy
    {
        public ProxyObjectType NativeClassType;
        public void* NativeEngineProxy;
        public Int32 EngineID;
        public Int32 ObjectID;
        public void* NativeObjectTemplate;
    }

    // ========================================================================================================================

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public unsafe struct NativeFunctionTemplateProxy
    {
        public ProxyObjectType NativeClassType;
        public void* NativeEngineProxy;
        public Int32 EngineID;
        public void* NativeFucntionTemplate;
    }

    // ========================================================================================================================

    [StructLayout(LayoutKind.Sequential, Pack = 1)]
    public unsafe struct ManagedAccessorInfo
    {
        public NativeObjectTemplateProxy* NativeObjectTemplateProxy;
        /// <summary>始终将其设置为与从模板创建的对象的回调过程相关联的管理对象ID（索引）。</summary>
        public Int32 ManagedObjectID;

    }

    // ========================================================================================================================

    [StructLayout(LayoutKind.Explicit, Pack = 1, Size = 68)]
    public unsafe struct HandleProxy
    {
        // --------------------------------------------------------------------------------------------------------------------
        // 本机字段

        [FieldOffset(0), MarshalAs(UnmanagedType.I4)]
        public ProxyObjectType NativeClassType;
        /// <summary>此句柄代理的本机ID（索引）。</summary>
        [FieldOffset(4), MarshalAs(UnmanagedType.I4)]
        public Int32 ID;
        /// <summary>如果设置为（> = 0），则将托管对象与此句柄关联。 默认值为-1。</summary>
        [FieldOffset(8), MarshalAs(UnmanagedType.I4)]
        public Int32 _ObjectID;
        /// <summary>如果设置（> = 0），则表示已注册类型。 默认值为-1。</summary>
        [FieldOffset(12), MarshalAs(UnmanagedType.I4)]
        public Int32 _CLRTypeID;
        /// <summary>32位值类型，即此句柄表示的类型。 在调用“ GetType（）”之前，默认情况下不提供此功能。</summary>
        [FieldOffset(16), MarshalAs(UnmanagedType.I4)]
        public JSValueType _ValueType;

        #region ### HANDLE VALUE ### - 注意:这仅在调用'UpdateValue()'时有效.
        [FieldOffset(20), MarshalAs(UnmanagedType.I1)]
        public Byte V8Boolean;
        /// <summary>（JavaScript仅支持32位整数，但这是保持本地联合的预期编组大小所必需的）</summary>
        [FieldOffset(20), MarshalAs(UnmanagedType.I8)]
        public Int64 V8Integer;
        /// <summary>（也用于自纪元[1970年1月1日00:00:00]起的Date毫秒）</summary>
        [FieldOffset(20)]
        public double V8Number;
        /// <summary>（对于字符串和对象，这是ToString（）值[Unicode字符（每个2个字节）]）</summary>
        [FieldOffset(28)]
        public void* V8String;
        #endregion

        [FieldOffset(36), MarshalAs(UnmanagedType.I8)]
        public Int64 ManagedReferenceCount; // The number of references on the managed side.
        /// <summary>（0 =正在使用，1 =已准备好被管理方，2 =对象弱（如果适用），3 =已处理/已缓存）</summary>
        [FieldOffset(44), MarshalAs(UnmanagedType.I4)]
        public Int32 Disposed;

        [FieldOffset(48), MarshalAs(UnmanagedType.I4)]
        public Int32 EngineID;
        /// <summary>指向与此代理句柄实例关联的本机V8引擎代理对象的指针（用于本机端以在销毁时释放该句柄）。</summary>
        [FieldOffset(52)]
        public void* NativeEngineProxy;
        /// <summary>本机V8持久对象句柄（不在托管端使用）。</summary>
        [FieldOffset(60)]
        public void* NativeV8Handle;

        // --------------------------------------------------------------------------------------------------------------------
        // 字段解释的属性。

        public bool IsDisposeReady
        {
            get { return Disposed == 1 || Disposed == 2; }
            set { if (Disposed <= 1) Disposed = value ? 1 : 0; } //（一旦处置>1，将无法停止该进程）
        }

        public bool IsWeak { get { return Disposed == 2; } }

        public bool IsDisposed { get { return Disposed == 3; } }

        // --------------------------------------------------------------------------------------------------------------------

        public object Value
        {
            get
            {
                if ((int)_ValueType == -1) throw new InvalidOperationException("类型未知-您必须先调用'V8NetProxy.UpdateHandleValue()'");
                switch (_ValueType)
                {
                    case JSValueType.Undefined: return "undefined";
                    case JSValueType.Null: return null;
                    case JSValueType.Bool: return !(V8Boolean == 0);
                    case JSValueType.BoolObject: return V8Boolean; // TODO: Test this.
                    case JSValueType.Int32: return (Int32)V8Integer;
                    case JSValueType.Number: return V8Number;
                    case JSValueType.NumberObject: return V8Number; // TODO: Test this.
                    default: return V8String != null ? Marshal.PtrToStringUni((IntPtr)V8String) : null;
                }
            }
        }

        // --------------------------------------------------------------------------------------------------------------------
    }

    // ========================================================================================================================

    /// <summary>NamedProperty [Getter | Setter]用作对象的拦截器。 请参见ObjectTemplate::SetNamedPropertyHandler。</summary>
    [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
    public unsafe delegate HandleProxy* ManagedNamedPropertyGetter(string propertyName, ref ManagedAccessorInfo info);

    /// <summary>如果设置器拦截了请求，则返回值。 否则，返回一个空句柄。</summary>
    [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
    public unsafe delegate HandleProxy* ManagedNamedPropertySetter(string propertyName, HandleProxy* value, ref ManagedAccessorInfo info);

    /// <summary>如果拦截器拦截了请求，则返回一个非空值(>=0)。 结果是对属性属性进行整数编码(例如v8::None,v8::DontEnum等)</summary>
    [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
    public unsafe delegate V8PropertyAttributes ManagedNamedPropertyQuery(string propertyName, ref ManagedAccessorInfo info);

    /// <summary>返回一个值，该值指示删除程序是否拦截请求。 如果可以删除该属性，则返回值为true（> 0），否则返回false（0）。</summary>
    [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
    public unsafe delegate int ManagedNamedPropertyDeleter(string propertyName, ref ManagedAccessorInfo info);
    /// <summary>
    /// 返回一个数组，其中包含命名属性getter拦截的属性的名称。
    /// </summary>
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    public unsafe delegate HandleProxy* ManagedNamedPropertyEnumerator(ref ManagedAccessorInfo info);

    // ------------------------------------------------------------------------------------------------------------------------

    /// <summary>
    /// 如果getter截获__stdcall，则返回属性的值
    /// </summary>
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    public unsafe delegate HandleProxy* ManagedIndexedPropertyGetter(Int32 index, ref ManagedAccessorInfo info);

    /// <summary>
    /// 如果设置器拦截了请求，则返回值。 否则，返回一个空句柄。
    /// </summary>
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    public unsafe delegate HandleProxy* ManagedIndexedPropertySetter(Int32 index, HandleProxy* value, ref ManagedAccessorInfo info);

    /// <summary>
    /// 如果拦截器拦截了请求，则返回一个非空值（>=0）。 结果是一个整数编码属性的属性。
    /// </summary>
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    public unsafe delegate V8PropertyAttributes ManagedIndexedPropertyQuery(Int32 index, ref ManagedAccessorInfo info);

    /// <summary>
    /// 返回一个值，该值指示删除程序是否拦截请求。 如果可以删除该属性，则返回值为true（> 0），否则返回false（0）。
    /// </summary>
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    public unsafe delegate int ManagedIndexedPropertyDeleter(Int32 index, ref ManagedAccessorInfo info);

    /// <summary>
    /// 返回一个数组，其中包含索引属性getter所拦截的属性的索引。
    /// </summary>
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    public unsafe delegate HandleProxy* ManagedIndexedPropertyEnumerator(ref ManagedAccessorInfo info);

    // ========================================================================================================================

    /// <summary>
    /// 如果设置器拦截了请求，则返回值。 否则，返回一个空句柄。
    /// </summary>
    [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
    public unsafe delegate HandleProxy* ManagedAccessorSetter(HandleProxy* _this, string propertyName, HandleProxy* value);

    /// <summary>
    /// 如果设置器拦截了请求，则返回值。 否则，返回一个空句柄。
    /// </summary>
    [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)]
    public unsafe delegate HandleProxy* ManagedAccessorGetter(HandleProxy* _this, string propertyName);

    // ========================================================================================================================

    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    public unsafe delegate HandleProxy* ManagedJSFunctionCallback(Int32 managedObjectID, bool isConstructCall, HandleProxy* _this, HandleProxy** args, Int32 argCount);
    // ('IntPtr' == HandleProxy*)

    // ========================================================================================================================

    /// <summary>
    /// 拦截垃圾回收与指定代理句柄关联的持久V8句柄的请求。 返回true允许收集，返回false阻止收集。
    /// 注意：在内部，这用于删除对托管对象的强引用，仅保留一周的时间。
    /// </summary>
    [UnmanagedFunctionPointer(CallingConvention.StdCall)]
    public unsafe delegate bool V8GarbageCollectionRequestCallback(HandleProxy* objectToBeCollected);

    // ========================================================================================================================
}
